﻿using Common;
using Decoder.Scorer;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace Decoder.Search
{
    /// <summary>
    /// Manager for pruned hypothesis
    /// </summary>
    public class AlternateHypothesisManager : IAlternateHypothesisManager
    {
        private Dictionary<IToken, List<IToken>> viterbiLoserMap = new Dictionary<IToken, List<IToken>>();
        private int maxEdges=0;
        /// <summary>
        /// Creates an alternate hypotheses manager 
        /// </summary>
        /// <param name="maxEdges">the maximum edges allowed</param>
        public AlternateHypothesisManager(int maxEdges) 
        {
            this.maxEdges = maxEdges;
        }

        /// <summary>
        /// Collects adds alternate predecessors for a token that would have lost because of viterbi.
        /// </summary>
        /// <param name="token">a token that has an alternate lower scoring predecessor that still might be of interest</param>
        /// <param name="predecessor">a predecessor that scores lower than token.getPredecessor().</param>
        public void addAlternatePredecessor(IToken token, IToken predecessor) 
        {
            Trace.Assert(predecessor != token.getPredecessor());
            List<IToken> list = viterbiLoserMap[token];
            if (list == null) 
            {
                list = new List<IToken>();
                viterbiLoserMap.Add(token, list);
            }
            list.Add(predecessor);
        }
        /// <summary>
        /// Returns a list of alternate predecessors for a token.
        /// </summary>
        /// <param name="token">a token that may have alternate lower scoring predecessor that still might be of interest</param>
        /// <returns>A list of predecessors that scores lower than token.getPredecessor().</returns>
        public List<IToken> getAlternatePredecessors(IToken token) 
        {
            return viterbiLoserMap[token];
        }

        /// <summary>
        /// Purge all but max number of alternate preceding token hypotheses. 
        /// </summary>
        public void purge() 
        {
            int max = maxEdges - 1;

            foreach (KeyValuePair<IToken, List<IToken>> entry in viterbiLoserMap) 
            {
                List<IToken> list = entry.Value;
                list.Sort(); //you must use default comparer
                List<IToken> newList = (list.Take(list.Count > max ? max : list.Count)).ToList<IToken>();
                viterbiLoserMap.Add(entry.Key, newList);
            }
        }
        /// <summary>
        /// Change the successor from one token to another
        /// </summary>
        /// <param name="newSuccessor">the new successor token</param>
        /// <param name="oldSuccessor">the old successor token</param>
        public void changeSuccessor(IToken newSuccessor, IToken oldSuccessor) 
        {
            List<IToken> list = viterbiLoserMap[oldSuccessor];
            viterbiLoserMap.Add(newSuccessor, list);
            viterbiLoserMap.Remove(oldSuccessor);
        }


	    public Boolean hasAlternatePredecessors(IToken token) 
        {
		    return viterbiLoserMap.ContainsKey(token);
	    }
    }
}
